package dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;

@SuppressWarnings("unchecked")
public abstract class GenericDAO<T extends Serializable> {

    private static Log LOG = LogFactory.getLog(GenericDAO.class);    
    private final EntityManager entityManager;
    
	protected EntityManager getEntityManager() {
		return entityManager;
	}

	public GenericDAO() {
		EntityManagerFactory factory = Persistence.createEntityManagerFactory("siacom");
    	entityManager = factory.createEntityManager();    	
    }    

    public Class<?> getPersistentClass() {
    	Class<?> clazz = (Class<?>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        return clazz;
    }
        
    public void salvar(T entity) {
        try {
            entityManager.getTransaction().begin();
            entityManager.persist(entity);
            entityManager.getTransaction().commit();
        }  catch (Exception ex) {
            GenericDAO.LOG.error(ex);
            entityManager.getTransaction().rollback();
        } finally {
        	closeEntityManager();
        }
    }

    public void excluir(T entity) {
    	try {
    		entityManager.getTransaction().begin();
    		entityManager.remove(entity);
    		entityManager.getTransaction().commit();
    	} catch (Exception ex) {
    		GenericDAO.LOG.error(ex);
    		entityManager.getTransaction().rollback();
    	} finally {
    		closeEntityManager();
    	}
    }
    
    public void atualizar(T entity) {
        try {
        	entityManager.getTransaction().begin();
            entityManager.merge(entity);
            entityManager.getTransaction().commit();
        } catch (Exception ex) {
    		GenericDAO.LOG.error(ex);
    		entityManager.getTransaction().rollback();
    	} finally {
    		closeEntityManager();
    	}  
    }
   
    public T getById(Long id) {  
    	return (T) entityManager.find(getPersistentClass(), id);
    }       
        
	public List<T> buscarTodos() {
        //return entityManager.createQuery(("From " + getPersistentClass().getName())).getResultList();
		return getSession().createCriteria(getPersistentClass()).list();
    }   
	
	protected Session getSession() {
		return (Session) entityManager.getDelegate();
	}

    public List<T> buscarListaPeloCriterio(Criterion... criterion) {
    	List<?> lista = null;
        try {            
            Criteria crit = getSession().createCriteria(getPersistentClass());
            for (Criterion c : criterion) crit.add(c);                    
            lista = crit.list();
        } catch (Exception ex) {
            GenericDAO.LOG.error(ex);
        }	   
        return (List<T>) lista;
    }  
    
    protected void closeEntityManager() {
        if (getEntityManager().isOpen()) {
            getEntityManager().close();
        }       
    }

}
